{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import interact, interactive, fixed, interact_manual\n",
    "import ipywidgets as widgets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OPTIONAL - More about interact\n",
    "\n",
    "This notebook describes more ways to autogenerate widgets."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `interactive`\n",
    "\n",
    "In addition to `interact`, IPython provides another function, `interactive`, that is useful when you want to reuse the widgets that are produced or access the data that is bound to the UI controls.\n",
    "\n",
    "Note that unlike `interact`, the return value of the function will not be displayed automatically, but you can display a value inside the function with `IPython.display.display`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is a function that displays the sum of its two arguments and returns the sum. The `display` line may be omitted if you don't want to show the result of the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import display\n",
    "\n",
    "def f(a, b):\n",
    "    display(a + b)\n",
    "    return a+b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Unlike `interact`, `interactive` returns a `Widget` instance rather than immediately displaying the widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w = interactive(f, a=10, b=20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The widget is an `interactive`, a subclass of `VBox`, which is a container for other widgets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(w)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The children of the `interactive` are two integer-valued sliders and an output widget, produced by the widget abbreviations above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.children"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To actually display the widgets, you can use IPython's `display` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(w)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At this point, the UI controls work just like they would if `interact` had been used. You can manipulate them interactively and the function will be called. However, the widget instance returned by `interactive` also gives you access to the current keyword arguments and return value of the underlying Python function. \n",
    "\n",
    "Here are the current keyword arguments. If you rerun this cell after manipulating the sliders, the values will have changed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.kwargs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is the current return value of the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w.result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Disabling continuous updates"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When interacting with long running functions, or even with short functions whose results take some to display, realtime feedback is a burden instead of being helpful. You might have noticed the output of some of the widgets above \"flickering\" as you adjusted the controls. By default, `interact` and `interactive` call the function for every update of the widgets value. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are two ways to mitigate this.  You can either only execute on demand, or restrict execution to mouse release events."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `interact_manual`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `interact_manual` function provides a variant of interaction that allows you to restrict execution so it is only done on demand.  A button is added to the interact controls that allows you to trigger an execute event."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def slow_function(i):\n",
    "    \"\"\"\n",
    "    Sleep for 1 second then print the argument\n",
    "    \"\"\"\n",
    "    from time import sleep\n",
    "    print('Sleeping...')\n",
    "    sleep(1)\n",
    "    print(i)\n",
    "\n",
    "interact_manual(slow_function,i=widgets.FloatSlider(min=1e4, max=1e6, step=1e4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can do the same thing with `interactive` by using a `dict` as the second argument, as shown below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "foo = interactive(slow_function, {'manual': True}, i=widgets.FloatSlider(min=1e4, max=1e6, step=1e4))\n",
    "foo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `continuous_update`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you are using slider widgets, you can set the `continuous_update` kwarg to `False`.  `continuous_update` is a keyword argument of slider widgets that restricts executions to mouse release events.\n",
    "\n",
    "In ipywidgets 7, the `Text` and `Textarea` controls also have a `continuous_update` argument.\n",
    "\n",
    "The first example below provides the `continuous_update` argument when the widget is created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(slow_function,i=widgets.FloatSlider(min=1e4, max=1e6, step=5e4, continuous_update=False));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## More control over the user interface: `interactive_output`\n",
    "\n",
    "`interactive_output` provides additional flexibility: you can control how the UI elements are laid out.\n",
    "\n",
    "Unlike `interact`, `interactive`, and `interact_manual`, `interactive_output` does not generate a user interface for the widgets. This is powerful, because it means you can create a widget, put it in a box, and then pass the widget to `interactive_output`, and have control over the widget and its layout."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = widgets.IntSlider()\n",
    "b = widgets.IntSlider()\n",
    "c = widgets.IntSlider()\n",
    "\n",
    "# An HBox lays out its children horizontally\n",
    "ui = widgets.HBox([a, b, c])\n",
    "\n",
    "def f(a, b, c):\n",
    "    # You can use print here instead of display because interactive_output generates a normal notebook \n",
    "    # output area.\n",
    "    print((a, b, c))\n",
    "\n",
    "out = widgets.interactive_output(f, {'a': a, 'b': b, 'c': c})\n",
    "\n",
    "display(ui, out)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# For more information \n",
    "\n",
    "For more extended examples of `interact` and `interactive`, see [the example in the ipywidgets source repository](https://github.com/jupyter-widgets/ipywidgets/blob/master/docs/source/examples/Index.ipynb)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "widgets-tutorial",
   "language": "python",
   "name": "widgets-tutorial"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
